﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

namespace QD.Cache
{
    public class CacheItemManager<T> where T : class,ICacheObject, new()
    {
        public CacheItemManager()
        {
            KEY_ITEM_FORMAT = "__jCache_" + typeof(T).FullName + ".{0}";
            cache_keys = new List<String>(100);
        }
        public readonly string KEY_ITEM_FORMAT = null;

        public int CacheTimeMinute { get; set; }

        IList<String> cache_keys = null;

        public T this[string key]
        {
            get
            {
                T item = default(T);

                item = HttpRuntime.Cache.Get(String.Format(KEY_ITEM_FORMAT, key)) as T;

                if (item == null && Resolver != null)
                {
                    if ((item = Resolver(key)) != null)
                        Add(item);
                }
                return item;
            }
        }
        public T this[Int32 key] { get { return this[key.ToString()]; } }
        public T this[Int64 key] { get { return this[key.ToString()]; } }

        public delegate T ResolveHandler(String key);

        public ResolveHandler Resolver = null;

        private void Add(T item)
        {
            String key = String.Format(KEY_ITEM_FORMAT, item.__get_cache_key());
            HttpRuntime.Cache.Insert(key, item, null, DateTime.Now.AddMinutes(CacheTimeMinute), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal,
                delegate(String str, object obj, System.Web.Caching.CacheItemRemovedReason reason)
                {
                    T _item = obj as T;
                    String _key = null;
                    for (int i = 0; i < cache_keys.Count; i++)
                    {
                        _key = cache_keys[i];
                        if (_key.Equals(_item.__get_cache_key().ToString()))
                            cache_keys.Remove(_key);
                    }
                });
            cache_keys.Add(item.__get_cache_key().ToString());
        }

        public void Replace(String key)
        {

            T item = Resolver(key);
            Remove(key);
            Add(item);

        }

        public void Replace(Int32 key) { Replace(key.ToString()); }
        public void Replace(Int64 key) { Replace(key.ToString()); }

        public void Replace(T item)
        {
            Remove(item.__get_cache_key());
            Add(item);
        }

        public void Remove(Object key)
        {
            HttpRuntime.Cache.Remove(String.Format(KEY_ITEM_FORMAT, key));
        }

        public IList<T> Find(Int32 top)
        {
            List<T> list = new List<T>(Math.Min(top, cache_keys.Count));
            Int32 i = 0;
            foreach (String key in cache_keys)
            {
                list.Add(this[key]);
                if (++i >= top) break;
            }
            return list;
        }

        public IList<T> Find(Predicate<T> p)
        {
            List<T> list = new List<T>();
            T item = default(T);
            foreach (String key in cache_keys)
            {
                item = this[key];
                if (item != null && p(item))
                    list.Add(item);
            }
            return list;
        }

        public IList<T> Items
        {
            get
            {
                List<T> list = new List<T>(cache_keys.Count);
                foreach (String key in cache_keys)
                {
                    list.Add(this[key]);
                }
                return list;
            }
        }

        public void Clear()
        {
            List<String> clone = new List<String>(cache_keys);
            foreach (var item in clone)
            {
                HttpRuntime.Cache.Remove(String.Format(KEY_ITEM_FORMAT, item));
            }
        }

    }
}
